/**
 * department服务实现
 *
 * @author sxf
 * @email sxf02615@163.com
 * @date 2025/1/15
 */
package com.sxf.crm.service.impl;

import com.sxf.crm.dto.DepartmentDTO;
import com.sxf.crm.dto.UserDTO;
import com.sxf.crm.entity.Department;
import com.sxf.crm.entity.User;
import com.sxf.crm.exception.ResourceNotFoundException;
import com.sxf.crm.repository.DepartmentRepository;
import com.sxf.crm.repository.UserRepository;
import com.sxf.crm.service.DepartmentService;

import lombok.RequiredArgsConstructor;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.ArrayList;

/**
 * 
 * @author sxf
 * @email sxf02615@163.com
 * @date 2025/6/1
 */
@Service
@RequiredArgsConstructor
@Transactional
public class DepartmentServiceImpl implements DepartmentService {

    private final DepartmentRepository departmentRepository;
    private final UserRepository userRepository;

    @Override
    @Transactional(readOnly = true)
    public List<Department> getAllDepartments(String name) {
        List<Department> departments;
        if (name != null && !name.isEmpty()) {
            departments = departmentRepository.findByNameContaining(name);
        } else {
            departments = departmentRepository.findAll();
        }
        
        // 为每个部门设置完整路径
        departments.forEach(dept -> {
            StringBuilder path = new StringBuilder(dept.getName());
            Department parent = dept.getParent();
            while (parent != null) {
                path.insert(0, parent.getName() + " / ");
                parent = parent.getParent();
            }
            dept.setFullPath(path.toString());
        });
        
        return departments;
    }

    @Override
    @Transactional(readOnly = true)
    public List<Department> getDepartmentTree() {
        List<Department> allDepartments = departmentRepository.findAll();
        // 确保所有部门数据都被加载
        allDepartments.forEach(dept -> {
            if (dept.getParent() != null) {
                dept.getParent().getName();
            }
        });
        return allDepartments.stream()
                .filter(dept -> dept.getParent() == null)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public Optional<Department> getDepartment(Long id) {
        return departmentRepository.findById(id).map(dept -> {
            if (dept.getParent() != null) {
                dept.getParent().getName();
            }
            return dept;
        });
    }

    @Override
    public Department saveDepartment(Department department) {
        // 检查是否存在同名部门
        if (department.getId() == null) {
            if (departmentRepository.existsByName(department.getName())) {
                throw new RuntimeException("部门名称已存在");
            }
        } else {
            Department existingDept = departmentRepository.findById(department.getId())
                    .orElseThrow(() -> new RuntimeException("部门不存在"));
            if (!existingDept.getName().equals(department.getName()) &&
                departmentRepository.existsByName(department.getName())) {
                throw new RuntimeException("部门名称已存在");
            }
        }

        // 检查父部门是否存在
        if (department.getParent() != null && department.getParent().getId() != null) {
            Department parent = departmentRepository.findById(department.getParent().getId())
                    .orElseThrow(() -> new RuntimeException("父部门不存在"));
            department.setParent(parent);
        }

        return departmentRepository.save(department);
    }

    @Override
    public void deleteDepartment(Long id) {
        Department department = departmentRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("部门不存在"));

        // 检查是否有子部门
        if (!department.getChildren().isEmpty()) {
            throw new RuntimeException("该部门下还有子部门，无法删除");
        }

        departmentRepository.deleteById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public Set<User> getDepartmentAndChildrenUsers(Long departmentId) {
        List<Department> departments = getDepartmentAndChildren(departmentId);
        List<Long> departmentIds = departments.stream()
            .map(Department::getId)
            .collect(Collectors.toList());
        return new HashSet<>(userRepository.findByDepartmentIdIn(departmentIds));
    }

    @Override
    public Set<Long> getUserDepartmentIds(String username) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("User not found"));

        return getDepartmentAndChildren(user.getDepartmentId()).stream()
            .map(Department::getId)
            .collect(Collectors.toSet());
    }

    @Override
    public List<Department> getDepartmentAndChildren(Long departmentId) {
        Department department = departmentRepository.findById(departmentId)
            .orElseThrow(() -> new RuntimeException("Department not found"));
            
        List<Department> result = new ArrayList<>();
        result.add(department);
        
        // 使用迭代而不是递归
        List<Department> toProcess = new ArrayList<>();
        toProcess.add(department);
        
        while (!toProcess.isEmpty()) {
            Department current = toProcess.remove(0);
            List<Department> children = departmentRepository.findByParentId(current.getId());
            result.addAll(children);
            toProcess.addAll(children);
        }
        
        return result;
    }

    @Override
    public List<Department> getDepartmentsByIds(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return List.of();
        }
        return departmentRepository.findAllById(ids);
    }

    @Override
    public Department findById(Long departmentId) {
        return departmentRepository.findById(departmentId)
            .orElseThrow(() -> new ResourceNotFoundException("Department not found with id: " + departmentId));
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<DepartmentDTO> getAllDepartmentsAsDTO(String name   ) {
        List<Department> departments;
        if (name != null && !name.isEmpty()) {
            departments = departmentRepository.findByNameContaining(name);
        } else {
            departments = departmentRepository.findAll();
        }
        return departments.stream()
            .map(DepartmentDTO::fromEntity)
            .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<UserDTO> getUsersByDepartmentAndChildren(Long departmentId) {
        Set<Long> departmentIds = getAllChildDepartmentIds(departmentId);
        departmentIds.add(departmentId);
        List<User> users = userRepository.findByDepartmentIdIn(new ArrayList<>(departmentIds));
        return users.stream()
            .map(UserDTO::fromEntity)
            .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Set<Long> getAllChildDepartmentIds(Long parentId) {
        Set<Long> childIds = new HashSet<>();
        List<Department> children = departmentRepository.findByParentId(parentId);
        for (Department child : children) {
            childIds.add(child.getId());
            childIds.addAll(getAllChildDepartmentIds(child.getId())); // Recursive call
        }
        return childIds;
    }
}
